module PNEngine
  class Token < ActiveRecord::Base
    include Resource::InstanceMethods
    extend Resource::ClassMethods
    
    belongs_to :place
    has_many :modtokens
    has_and_belongs_to_many :combinations
    validates_presence_of :place
    
    has_and_belongs_to_many :depending_transition_modes, :class_name => "TransitionMode"
    #one token can only be created by one transition mode
    belongs_to :creator_transition_mode, :class_name => "TransitionMode", :foreign_key => "transition_mode_id"
    
    belongs_to :case
    serialize :cached_locators, Hash
    
    after_create :set_uuid
    before_save :eliminate_xml_version

    belongs_to :user
    
    before_update :strip_value
    def strip_value
      self.value = self.value.strip if !self.value.blank?
    end
    
    # Deeper cloning for tokens
    def clone
      t = super
      t.case = self.case
      t.place = self.place
      return t
    end
    
    def initialize(attributes = nil, old_case = nil)
      super(attributes)
                
      if old_case.nil? then
        create_case
      else
        self.case = old_case
      end
      
    end
	
    def eliminate_xml_version
      #TODO a nicer remove of xml version!!
      self.value.gsub!('<?xml version="1.0"?>', "") if self.value
    end
    
    def set_uuid
      if !attribute_present?(:uuid)
        self.uuid = self.url.to_s 
        self.save!
      end
    end

    def create_case
      self.case  = Case.new
    end
    
    def title
      values["title"] || id
    end
    
    def inform_following_transitions
      place.arcs.select {|arc| arc.place_to_transition? }.each do |outgoing_arc|
        if (outgoing_arc.transition.active? && outgoing_arc.transition.manual_execution)
          outgoing_arc.transition.fire
        end
      end
    end

    # Produces Atom entry representation of Token
    def to_atom
      e = Atom::Entry.new
      e.id = uuid
      e.title = "Token #{id}"
      link = e.links.new
      link["rel"] = "edit"
      link["href"] = url
      e.content = value || ""
      e.content["type"] = "text"
      e
    end
    
    #Returns all attributes of token specified by locators
    def values
      if Merb::Config[:locator_caching]
        if self.cached_locators.nil?
          self.cached_locators = collect_locators
          save!
        end
        return self.cached_locators
      else
        return collect_locators
      end
    end
	
    #sets one specific locator at token to new value. Don't forget to save token afterwards
    def set_locator(locator, val)
      loc = place.locators.select{|loc| loc.name == locator}.first
      raise "No locator found for writing value in token" if loc.nil?
      self.value = loc.write(value, val)
      self.cached_locators = nil
      return self.value
    end

    def set_active(isActive)
      self.is_active = isActive
      #p "After assign ID:#{id}, Creating transition mode: #{creator_transition_mode.id}"
      self.save!
      modtokens.destroy_all
      combinations.destroy_all
    end
    
    # prevent changing active status directly
    #private :is_active=
    
    private
    # used by values method, collecting all attributes from locators
    def collect_locators
      vals = {}
      place.locators.collect do |locator|
        vals[locator.name] = locator.evaluate(value)
      end
      vals
    end
    
  end
end